<?php

declare(strict_types=1);

namespace App\CustHub\Service;

use App\Common\Robot\Robot;
use App\CustHub\Constants\ContactSourceConstants;
use App\CustHub\Constants\ContactStatusConstants;
use App\CustHub\Constants\SyncTaskStatusConstants;
use App\CustHub\Mapper\ChContactMapper;
use App\CustHub\Mapper\ChRobotMapper;
use App\CustHub\Mapper\ChSyncTaskMapper;
use App\CustHub\Model\ChContact;
use App\CustHub\Model\ChContactCorpTag;
use App\CustHub\Model\ChContactMobile;
use App\CustHub\Model\ChCorp;
use App\CustHub\Model\ChSyncTask;
use App\Robot\Service\RobotApiService;
use Hyperf\Collection\Collection;
use Hyperf\Coroutine\Coroutine;
use Hyperf\DbConnection\Db;
use Hyperf\Di\Annotation\Inject;
use function Hyperf\Collection\collect;

class ChContactSyncService
{

    #[Inject]
    protected ChContactMapper $mapper;

    #[Inject]
    protected ChRobotMapper $robotMapper;

    #[Inject]
    protected ChSyncTaskMapper $syncTaskMapper;

    /**
     * 批量同步联系人
     * @param ChSyncTask $taskInfo
     * @param $currentSeq
     * @return void
     */
    public function batchSyncContacts(ChSyncTask $taskInfo, $currentSeq = 0)
    {
        $robotId = $taskInfo->robot_id;
        $robotInfo = $this->robotMapper->findById($robotId);
        if(empty($robotInfo) || !$robotInfo->login_status){
            $this->updateSyncTask($taskInfo->id, $currentSeq);
            return;
        }
        $robotApiService = make(Robot::class,[$robotInfo->server_id,$robotInfo->uuid])->gateway();

        $hasMore = true;
        $isProcessContactSync = true;
        $syncBatchId = 'sync_' . time() . '_' . uniqid();
        $contactSourceList = ContactSourceConstants::getConstants();
        stdout_log()->info("机器人{$robotId}同步客户开始");
        while ($hasMore){
            $response = $robotApiService->getContactList($currentSeq,100);
            if($response === false){
                //存在获取失败的情况则不继续处理，防止用户数据丢失
                stdout_log()->info("机器人{$robotId}同步客户失败".$robotApiService->getErrorMsg());
                $isProcessContactSync = false;
                break;
            }
            $contactList = $response['contact_list'];

            //用户标签
            $labelsToSync = collect($contactList)->filter(fn($c) => !empty($c['label_list']))
                ->map(fn($c) => ['user_id' => $c['user_id'], 'label_list' => $c['label_list']]);

            $contactList = collect($contactList)->filter(function ($collect){
                return !in_array($collect['contact_type'],[0,8]);
            })->map(function ($collect) use ($robotInfo,$contactSourceList,$syncBatchId){
                $corp_full_name = empty($collect['corp_name']) && empty($collect['corp_full_name']) ? "微信联系人" : $collect['corp_full_name'];
                $corp_name = empty($collect['corp_name']) ? "微信" : $collect['corp_name'];
                $collect['robot_id'] = $robotInfo['id'];
                $collect['uid'] = $robotInfo['uid'];
                $collect['main_uid'] = $robotInfo['main_uid'];
                $collect['type'] = 1;
                $collect['robot_corp_id'] = $robotInfo['corp_id'];
                $collect['alias'] =!empty($collect['alias']) ? $collect['alias'] : '';
                $collect['remark'] = !empty($collect['remark']) ? $collect['remark'] : '';
                $collect['desc'] = !empty($collect['desc']) ? $collect['desc'] : '';
                $collect['avatar'] = $collect['avatar_url'];
                $collect['corp_wxid'] = $collect['corp_id'];
                $collect['corp_id'] = 0;
                $collect['corp_short_name'] =$corp_name;
                $collect['corp_name'] = $corp_full_name;
                $collect['is_wechat'] = $corp_name == '微信' ? 1 : 0;
                $collect['mobile_list'] = !empty($collect['mobile_remark']) ? json_encode($collect['mobile_remark']) : null;
                //状态
                $status = ContactStatusConstants::getStatus($collect['contact_type']);
                $collect['status'] = $status;
                $collect['sync_batch_id'] = $syncBatchId;

                $addTime = $collect['add_time'] ?? time();
                if(empty($collect['create_time'])){
                    $collect['create_time'] = $addTime;
                }

                if(empty($collect['add_customer_time'])){
                    $collect['add_customer_time'] = $addTime;
                }

                if (!empty($collect['source_info'])) {
                    $addSource = $collect['source_info']['add_source'] ?? 0;
                    !in_array($addSource, $contactSourceList) && $addSource = 0;
                    $collect['source'] = $addSource;
                }
                $collect['source_info'] = json_encode($collect['source_info']);
                $this->mapper->filterExecuteAttributes($collect, $this->mapper->getModel()->incrementing);
                $this->mapper->rmCache($robotInfo['id'],$collect['user_id']);
                return $collect;
            });

            //存储更新用户数据
            $this->upsertContacts($contactList);

            //用户手机号
            $mobileMap = $contactList->filter(fn($c) => !empty($c['mobile_list']))
                ->mapWithKeys(fn($c) => [$c['user_id'] => json_decode($c['mobile_list'], true)]);
            $this->processRelatedData($contactList, $mobileMap, $labelsToSync, $robotInfo);
            $currentSeq = $response['current_seq'];
            $hasMore = $response['has_more'];
            Coroutine::sleep(rand(2,5));
        }
        stdout_log()->info("机器人{$robotId}同步客户结束");
        if(!$isProcessContactSync){
            $currentSeq = 0;
        }else{
            $this->pushDelayDeleteJob($robotInfo->id, $syncBatchId);
        }
        $this->updateSyncTask($taskInfo->id, $currentSeq);
    }

    private function pushDelayDeleteJob(int $robotId, string $currentBatchId): void
    {
        Coroutine::create(function () use ($robotId, $currentBatchId) {
            $query = ChContact::query()
                ->where('robot_id', $robotId)
                ->where('sync_batch_id', '<>', $currentBatchId);

            $query->chunkById(1000, function ($contacts) {
                $contactIds = $contacts->pluck('id')->toArray();
                ChContactMobile::whereIn('contact_id', $contactIds)->delete();
                ChContactCorpTag::whereIn('contact_id', $contactIds)->delete();
                ChContact::query()->whereIn('id', $contactIds)->delete();
                foreach ($contacts as $contact){
                    $this->mapper->rmCache($contact->robot_id,$contact->user_id);
                }
            });
        });
    }

    /**
     * 使用高效 UPSERT 处理联系人
     */
    protected function upsertContacts($processedContacts)
    {
        ChContact::upsert(
            $processedContacts->toArray(),
            ['robot_id', 'user_id']
        );
    }

    /**
     * 处理关联数据（手机号、标签）
     */
    protected function processRelatedData($contacts, $mobileMap, $labelsToSync, $robotInfo)
    {
        $userIds = $contacts->pluck('user_id');

        // 本地 contact_id 映射
        $contactIds = ChContact::query()
            ->where('robot_id', $robotInfo->id)
            ->whereIn('user_id', $userIds)
            ->pluck('id', 'user_id');

        /**
         * 1. 处理手机号
         */
        $mobileDataFromApi = collect($mobileMap)->map(function ($mobiles, $userId) use ($contactIds) {
            return collect($mobiles)->map(fn($m) => [
                'contact_id' => $contactIds[$userId] ?? null,
                'mobile' => $m
            ]);
        })->flatten(1)->filter();

        if ($mobileDataFromApi->isNotEmpty()) {
            $contactIdsArr = $mobileDataFromApi->pluck('contact_id')->unique()->filter()->toArray();

            // 本地已存手机号
            $localMobiles = ChContactMobile::query()
                ->whereIn('contact_id', $contactIdsArr)
                ->get()
                ->groupBy('contact_id');

            $toInsert = [];
            $toDelete = [];

            foreach ($mobileDataFromApi->groupBy('contact_id') as $contactId => $newMobiles) {
                $newSet = collect($newMobiles)->pluck('mobile')->unique();
                if(isset($localMobiles[$contactId])){
                    $oldSet = $localMobiles[$contactId]->pluck('mobile')->unique();
                }else{
                    $oldSet = collect();
                }

                // 新增
                foreach ($newSet->diff($oldSet) as $m) {
                    $toInsert[] = ['contact_id' => $contactId, 'mobile' => $m];
                }
                // 删除
                foreach ($oldSet->diff($newSet) as $m) {
                    $toDelete[] = ['contact_id' => $contactId, 'mobile' => $m];
                }
            }

            DB::transaction(function () use ($toInsert, $toDelete) {
                if (!empty($toDelete)) {
                    foreach ($toDelete as $item) {
                        ChContactMobile::where('contact_id', $item['contact_id'])
                            ->where('mobile', $item['mobile'])
                            ->delete();
                    }
                }
                if (!empty($toInsert)) {
                    ChContactMobile::insertOrIgnore($toInsert);
                }
            });
        }else{
            ChContactMobile::whereIn('contact_id', $contactIds->values())->delete();
        }

        /**
         * 2. 处理标签
         */
        $tagDataFromApi = collect($labelsToSync)->map(function ($item) use ($contactIds) {
            return collect($item['label_list'])->map(fn($labelId) => [
                'contact_id' => $contactIds[$item['user_id']] ?? null,
                'corp_tag_id' => $labelId['label_id']
            ]);
        })->flatten(1)->filter();

        if ($tagDataFromApi->isNotEmpty()) {
            $contactIdsArr = $tagDataFromApi->pluck('contact_id')->unique()->filter()->toArray();

            // 本地已存标签
            $localTags = ChContactCorpTag::query()
                ->whereIn('contact_id', $contactIdsArr)
                ->get()
                ->groupBy('contact_id');

            $toInsert = [];
            $toDelete = [];

            foreach ($tagDataFromApi->groupBy('contact_id') as $contactId => $newTags) {
                $newSet = collect($newTags)->pluck('corp_tag_id')->unique();
                if(isset($localTags[$contactId])){
                    $oldSet = $localTags[$contactId]->pluck('corp_tag_id')->unique();
                }else{
                    $oldSet = collect();
                }

                // 新增
                foreach ($newSet->diff($oldSet) as $m) {
                    $toInsert[] = ['contact_id' => $contactId, 'corp_tag_id' => $m];
                }
                // 删除
                foreach ($oldSet->diff($newSet) as $m) {
                    $toDelete[] = ['contact_id' => $contactId, 'corp_tag_id' => $m];
                }
            }

            DB::transaction(function () use ($toInsert, $toDelete) {
                if (!empty($toDelete)) {
                    foreach ($toDelete as $item) {
                        ChContactCorpTag::where('contact_id', $item['contact_id'])
                            ->where('corp_tag_id', $item['corp_tag_id'])
                            ->delete();
                    }
                }
                if (!empty($toInsert)) {
                    ChContactCorpTag::insertOrIgnore($toInsert);
                }
            });
        }else{
            ChContactCorpTag::whereIn('contact_id', $contactIds->values())->delete();
        }
    }

    /**
     * 获取联系人来源（辅助方法）
     */
    protected function getContactSource($collect, $contactSourceList): int
    {
        if (empty($collect['source_info'])) return 0;

        $addSource = $collect['source_info']['add_source'] ?? 0;
        return in_array($addSource, $contactSourceList) ? $addSource : 0;
    }

    private function updateSyncTask(int $taskId, int $currentSeq): void
    {
        $this->syncTaskMapper->update($taskId, [
            'extra' => ['current_seq' => $currentSeq],
            'status' => SyncTaskStatusConstants::SUCCESS,
            'end_time' => time()
        ]);
    }

}